#
#   GameObjectManager.py
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; version 2 of the License.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   Copyright
#   Author: Nicholas F. Hoover
#   Contributors: Salvatore S. Gionfriddo
#   Created: 2007.06.20
#   Last Modified: 2007.07.24
#

import pygame, random
import GameObject
from EvilGreg import EvilGreg, DeadEvilGreg
from BasicKid import BasicKid
from FastKid import FastKid
from StrongKid import StrongKid
from FatKid import FatKid
from WeakKid import WeakKid
from Flame import Flame, Gas
from PowerUp import PowerUp
from Statistics import Statistics, EG_Stats

class GameObjectManager(object):

    def __init__(self, resourceManager):
        self.resourceManager = resourceManager
        self.evilGreg = EvilGreg()
        self.kids = pygame.sprite.OrderedUpdates()
        self.flames = pygame.sprite.RenderPlain()
        self.gases = pygame.sprite.RenderPlain()
        self.powerUps = pygame.sprite.OrderedUpdates()
        
        self.egStats = EG_Stats()
        self.level = -1

    def reset(self):
        self.evilGreg.reset()
        self.kids.empty()
        self.run = True
        self.resetSpawners()
        self.powerUps.empty()
        self.flames.empty()
        self.gases.empty()
        self.egStats.reset()
        self.level = -1

    def setSpawners(self, spawners):
        self.spawners = spawners
    def resetSpawners(self):
        if hasattr(self,'spawners'):
            for spawner in self.spawners:
                spawner.reset()
    def spawn(self):
        if hasattr(self,'spawners'):
            for spawner in self.spawners:
                spawner.spawn()
    def addSpawner(self, spawner):
        if hasattr(self, 'spawners'):
            self.spawners.append(spawner)
        else:
            self.spawners = [spawner]
        
    #update all the sprites, check for collisions and handle them, draw on the screen
    def update(self, screen):

        #add random kids on a timer
        self.spawn()
        
        self.egStats.increment([Statistics.TIME, self.egStats.levelFlag(self.level)])
        # collect collision boxes
        collision = []
        for kid in self.kids:
            collision.append(kid.collision_rect)
        #collision.append(self.evilGreg.collision_rect)

        # update objects
        self.powerUps.update()
        self.kids.update(self.evilGreg.rect, collision)
        self.evilGreg.update(collision)
        self.createFlame()
        self.flames.update()
        self.createGas()
        self.gases.update()
        self.checkCollisions()

        # draw
        self.powerUps.draw(screen)
        self.kids.draw(screen)
        screen.blit(self.evilGreg.image, self.evilGreg.rect)
        self.flames.draw(screen)
        self.gases.draw(screen)
         
    def checkCollisions(self):
        self.checkPunch()
        self.checkKick()
        self.checkFlame()
        self.checkGas()
        self.checkKidAttack()
        self.checkEvilGregEat()

        self.checkPickUp()
        
    def checkPunch(self):
        if self.evilGreg.isActionActive(EvilGreg.PUNCH):
            punch = self.evilGreg.createPunchSprite()
            kills = self.hitKids(pygame.sprite.spritecollide(punch,self.kids,False), EvilGreg.PUNCH_DAMAGE)
            for kidtype in kills:
                self.egStats.increment([Statistics.KILL, Statistics.PUNCH, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype])

    def checkKick(self):
        if self.evilGreg.isActionActive(EvilGreg.KICK):
            kick = self.evilGreg.createKickSprite()
            kills = self.hitKids(pygame.sprite.spritecollide(kick,self.kids,False), EvilGreg.KICK_DAMAGE)
            for kidtype in kills:
                self.egStats.increment([Statistics.KILL, Statistics.KICK, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype])
        
    def checkFlame(self):
        flameHitDict = pygame.sprite.groupcollide(self.flames, self.kids, False, False)
        for flame in flameHitDict:
            if flame.isActionActive(Flame.FLAME):
                kills = self.hitKids(flameHitDict[flame],EvilGreg.FLAME_DAMAGE)
                for kidtype in kills:
                    self.egStats.increment([Statistics.KILL, Statistics.FLAME, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype])

    def checkGas(self):
        gasHitDict = pygame.sprite.groupcollide(self.gases, self.kids, False, False)
        for gas in gasHitDict:
            if gas.isActionActive(Gas.GAS):
                kills = self.hitKids(gasHitDict[gas],EvilGreg.GAS_DAMAGE)
                for kidtype in kills:
                    self.egStats.increment([Statistics.KILL, Statistics.GAS, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype])


    def hitKids(self, kidList, totalDamage):
        kills = {}
        for kid in kidList[:]:
            if totalDamage > 0:
                self.resourceManager.playSound('Kid_Crunch')
                
                if kid.health <= totalDamage:
                    totalDamage -= kid.health
                    kid.decHealth(kid.health)
                else:
                    kid.decHealth(totalDamage)
                    totalDamage = 0
                
                if not kid.isAlive():
                    self.addDeadKid(kid)
                    kidtype = kid.__class__.__name__
                    if kidtype in kills:
                        kills[kidtype] += 1
                    else:
                        kills.update([(kidtype, 1)])
                    kid.kill()
                    self.resourceManager.playSound('Kid_Die')
        return kills

    def checkEvilGregEat(self):
        if self.evilGreg.isActionActive(EvilGreg.EAT):
            eat = self.evilGreg.createEatSprite()
            self.eatPowerUps(pygame.sprite.spritecollide(eat, self.powerUps, False))
    
    def eatPowerUps(self, puList):
        for powerUp in puList[:EvilGreg.MAX_POWERUPS_EAT]:
            flags = [Statistics.EAT, self.egStats.powerUpFlag(powerUp.currentAnimation - powerUp.facing), self.egStats.levelFlag(self.level)]
            if powerUp.isDrugs():
                self.resourceManager.playSound('EG_Drugs')
            elif powerUp.isDeadKid():
                self.resourceManager.playSound('EG_Eat')
                flags.append(Statistics.ENEMY)
            else:
                self.resourceManager.playSound('EG_Eat')
                flags.append(Statistics.POWERUP)
            for effect in powerUp.effects:
                self.evilGreg.addEffect(effect)
            self.egStats.increment(flags)
            powerUp.kill()
            
    def checkPickUp(self):
        if self.evilGreg.isActionActive(EvilGreg.PICKUP):
            pickup = self.evilGreg.createEatSprite()
            powerUps = pygame.sprite.spritecollide(pickup, self.powerUps, False)
            for powerUp in powerUps[:EvilGreg.MAX_POWERUPS_PICKUP]:
                self.evilGreg.addItem(powerUp.currentAnimation-powerUp.facing)
                powerUp.kill()

    def checkKidAttack(self):
        kids = pygame.sprite.spritecollide(self.evilGreg,self.kids,False)
        for kid in kids:
            if kid.isActionActive(kid.BITE):
                self.resourceManager.playSound('Kid_Bite')
                self.evilGreg.decHealth(kid.BITE_DAMAGE)

    def createFlame(self):
        if self.evilGreg.isActionActive(EvilGreg.FLAME):
            flame = Flame()
            if self.evilGreg.facing == EvilGreg.RIGHT:
                flame.setPosition((self.evilGreg.rect.left + 50, self.evilGreg.rect.top + 30))
            else:
                flame.setPosition((self.evilGreg.rect.left - flame.rect.width + 10, self.evilGreg.rect.top + 30))
                flame.facing = Flame.LEFT
            flame.flame()
            self.flames.add(flame)
            self.resourceManager.playSound('Flame')            

    def createGas(self):
        if self.evilGreg.isActionActive(EvilGreg.GAS):
            gas = Gas()
            if self.evilGreg.facing == EvilGreg.RIGHT:
                gas.setPosition((self.evilGreg.rect.left-60, self.evilGreg.rect.top + 60))
            else:
                gas.setPosition((self.evilGreg.rect.right-15, self.evilGreg.rect.top + 60))
                gas.facing = Gas.LEFT

            gas.gas()
            self.gases.add(gas)

    def addDeadKid(self, kid):
        """Add a new DeadKid to the field basic on the killing of the given kid"""
        #MAD HAX follow, proceed with caution
        if kid.__class__ == BasicKid:
            powerUpType = PowerUp.DEAD_BASIC_KID
        elif kid.__class__ == FastKid:
            powerUpType = PowerUp.DEAD_FAST_KID
        elif kid.__class__ == StrongKid:
            powerUpType = PowerUp.DEAD_STRONG_KID
        elif kid.__class__ == FatKid:
            powerUpType = PowerUp.DEAD_FAT_KID
        elif kid.__class__ == WeakKid:
            powerUpType = PowerUp.DEAD_WEAK_KID
        else:
            raise Exception('Could not find Kid type:', kid.__class__)
        
        if kid.facing == kid.LEFT:
            facing = PowerUp.LEFT
        else:
            facing = PowerUp.RIGHT
            
        newDeadKid = PowerUp(facing, powerUpType)
        newDeadKid.setPosition((kid.rect.left-10,kid.rect.top+20))
        self.powerUps.add(newDeadKid)
        self.powerUps._spritelist.sort(GameObject.gameObjectPosCompare)

    def addKid(self):
        self._addKid(BasicKid())
        
    def addFastKid(self):
        self._addKid(FastKid())

    def addStrongKid(self):
        self._addKid(StrongKid())
    
    def addFatKid(self):
        self._addKid(FatKid())
    
    def addWeakKid(self):
        self._addKid(WeakKid())
        
    def _addKid(self, newKid):
        newKid.setPosition(self.getRandomEdgeCoords())
        self.kids.add(newKid)
        self.kids._spritelist.sort(GameObject.gameObjectPosCompare)

    def getRandomEdgeCoords(self):
        xy_min = 0
        x_max = 800
        y_max = 600
        x = random.randrange(800)
        y = random.randrange(600)
        choices = [(x,xy_min), (x,y_max), (xy_min,y), (x_max,y)]
        (x,y) = random.choice(choices)
        return (x,y)
        
    def getRandomInternalCoords(self):
        x = random.randrange(30,770)
        y = random.randrange(30,570)
        return (x,y)
        
    def _addPowerUp(self, powerUpType):
        newPowerUp = PowerUp(PowerUp.RIGHT, powerUpType)
        newPowerUp.setPosition(self.getRandomInternalCoords())
        self.powerUps.add(newPowerUp)
        self.powerUps._spritelist.sort(GameObject.gameObjectPosCompare)
    def addDrugs(self):
        self._addPowerUp(PowerUp.DRUGS)
    def addPizza(self):
        self._addPowerUp(PowerUp.PIZZA)
    def addIndian(self):
        self._addPowerUp(PowerUp.INDIAN)
    def addTacos(self):
        self._addPowerUp(PowerUp.TACOS)
        
    #this is a little bit #HACKS
    def killEG(self, screen):
        deadEG = DeadEvilGreg()
        if self.evilGreg.facing == EvilGreg.LEFT:
            deadEG.setFacing(DeadEvilGreg.LEFT)
        else: deadEG.setFacing(DeadEvilGreg.RIGHT)
        deadEG.currentAnimation = DeadEvilGreg.DEAD + deadEG.facing
        deadEG.setPosition((self.evilGreg.rect.left, self.evilGreg.rect.bottom - 60))
        deadEG.update()
        self.powerUps.draw(screen)
        self.kids.draw(screen)
        screen.blit(deadEG.image, deadEG.rect)
        self.flames.draw(screen)
        self.gases.draw(screen)

